莫队算法

百度文库

题意

求一个区间中的子区间的值亦或等于k,问区间个数。

思路

  1. [i,j]区间亦或值等于[0,i-1]^[0,j]
  2. 让起点减一,方便完成莫队排序和第一步的计算
  3. [i,j]亦或值==k,则[0,j]^k==[0,i-1],用sum记录
  4. add函数,先答案增加后,更新,因为加的是之前存在的状态
  5. del函数,先更新后答案减少,因为减的是当前的值和它带来的状态

AC代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <complex>
#include <cstdio>
using namespace std;
#define ll long long
#define N 100010
ll a[N],n,m,k,num[1<<20],cnt[N];
ll len,ans;
struct modui
{
ll l,r,id;
bool operator < (const modui & b)const{
return (l/len==b.l/len)? r<b.r : l<b.l ;
}
}pr[N];
void add(ll x){
ans += num[x^k];
num[x]++;
}
void del(ll x){
num[x]--;
ans -= num[x^k];
}
void work(){
ll l=2,r=1;ans=0;
for(int i = 1 ; i <= m ;i++ ){
while(pr[i].r>r)add(a[++r]);
while(pr[i].r<r)del(a[r--]);
while(pr[i].l>l)del(a[l++]);
while(pr[i].l<l)add(a[--l]);
cnt[pr[i].id]=ans;
}
for(int i=1; i<=m ;i++)
printf("%I64d\n",cnt[i]);
}
int main(){
ll tmpa,tmpb;
while(~scanf("%I64d%I64d%I64d",&n,&m,&k)){
memset(num,0,sizeof(num));
a[0]=0;len=ceil(sqrt(n*1.0));
for(int i=1 ; i<=n ;i++){
scanf("%I64d",&a[i]);
a[i] = a[i]^a[i-1];
}
for(int i=1 ; i<=m ;i++){
scanf("%I64d%I64d",&tmpa,&tmpb);
tmpa--;
pr[i].l=tmpa,pr[i].r=tmpb,pr[i].id=i;
}
sort(pr+1,pr+m+1);
work();
}
return 0;
}